package com.atguigu.ggkt.order.api;

import com.atguigu.ggkt.box.OrderBox;
import com.atguigu.ggkt.exception.GgktException;
import com.atguigu.ggkt.model.order.OrderInfo;
import com.atguigu.ggkt.order.service.OrderInfoService;
import com.atguigu.ggkt.order.service.impl.WxPayNotifyImpl_v3;
import com.atguigu.ggkt.order.service.impl.WxPayServiceImpl;
import com.atguigu.ggkt.order.service.impl.WxPayServiceImpl_v3;
import com.atguigu.ggkt.result.Result;
import com.atguigu.ggkt.utils.LogTool;
import com.atguigu.ggkt.utils.SpringTool;
import com.atguigu.ggkt.vo.order.OrderInfoQueryVo;
import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.core.exception.ValidationException;
import com.wechat.pay.java.core.notification.NotificationConfig;
import com.wechat.pay.java.core.notification.NotificationParser;
import com.wechat.pay.java.service.payments.jsapi.model.PrepayWithRequestPaymentResponse;
import com.wechat.pay.java.service.payments.model.Transaction;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import com.wechat.pay.java.core.notification.RequestParam;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.Map;
import java.util.Objects;

@Api(tags = "微信支付接口")
@RestController
@RequestMapping("/api/order/wxPay")
public class WxPayController {

    @Autowired
    private WxPayServiceImpl wxPayServiceImpl;
    @Autowired
    private WxPayServiceImpl_v3 wxPayServiceImpl_v3;
    @Autowired
    private OrderInfoService orderInfoService;

    @ApiOperation(value = "查询支付状态")
    @GetMapping("/queryPayStatus/{orderNo}")
    public Result queryPayStatus(
            @ApiParam(name = "orderNo", value = "订单No", required = true)
            @PathVariable("orderNo") String orderNo) {

        LogTool.info(this.getClass(), "queryPayStatus orderNo: "+orderNo);
        OrderBox orderBox = new OrderBox();
        wxPayServiceImpl_v3.setOrderBox(orderNo, orderBox);
        //根据订单号调用微信接口查询支付状态
        Transaction transaction = wxPayServiceImpl_v3.queryPayStatus(orderNo, orderBox);
        orderBox.setTransaction(transaction);

        //判断支付是否成功：根据微信支付状态接口判断
        if(transaction == null) {
            throw new GgktException(20001,"支付出错");
        }

        if ("SUCCESS".equals(transaction.getTradeState().name())) {//成功
            //更新订单状态 ：已经支付
            String out_trade_no = transaction.getOutTradeNo();
            orderInfoService.updateOrderStatus(out_trade_no, orderBox);
            return Result.ok(null).message("支付成功");
        }
        return Result.ok(null).message("支付中");
    }

    @ApiOperation(value = "Jsapi下单程序支付")
    @GetMapping("/createJsapi/{orderNo}")
    @Deprecated
    public Result createJsapi(
            @ApiParam(name = "orderNo", value = "订单No", required = true)
            @PathVariable("orderNo") String orderNo) {
        Map<String,Object> map = wxPayServiceImpl.createJsapi(orderNo);
        return Result.ok(map);
    }

    @ApiOperation(value = "下单 小程序支付")
    @GetMapping("/createNative/{orderNo}")
    public Result createNative(
            @ApiParam(name = "orderNo", value = "订单No", required = true)
            @PathVariable("orderNo") String orderNo) {
        Map<String,Object> map = wxPayServiceImpl_v3.createNative(orderNo);
        return Result.ok(map);
    }

    @ApiOperation(value = "Jsapi下单程序支付demo")
    @GetMapping("/createJsapiDemo")
    public Result createJsapiDemo() throws IOException {
        PrepayWithRequestPaymentResponse response = wxPayServiceImpl_v3.createJsapiDemo();
        return Result.ok(response);
    }

    @ApiOperation(value = "Jsapiv3下单程序支付demo")
    @GetMapping("/createJsapiv3/{orderNo}")
    public Result createJsapiv3(@ApiParam(name = "orderNo", value = "订单No", required = true)
                                      @PathVariable("orderNo") String orderNo) throws Exception {
        LogTool.info(this.getClass(), "createJsapiDemo orderNo: "+orderNo);
        PrepayWithRequestPaymentResponse response = wxPayServiceImpl_v3.createJsapiv3(orderNo);
        return Result.ok(response);
    }

    /**
     * https://pay.weixin.qq.com/docs/merchant/apis/jsapi-payment/payment-notice.html
     */
    @ApiOperation(value = "微信支付回调")
    @PostMapping("/notify")
    public ResponseEntity<String> notify(
            @ApiParam(name = "requestBody", value = "回调报文json", required = true, example = "{\n" +
                    "    \"id\": \"EV-2018022511223320873\",\n" +
                    "    \"create_time\": \"2015-05-20T13:29:35+08:00\",\n" +
                    "    \"resource_type\": \"encrypt-resource\",\n" +
                    "    \"event_type\": \"TRANSACTION.SUCCESS\",\n" +
                    "    \"summary\": \"支付成功\",\n" +
                    "    \"resource\": {\n" +
                    "        \"original_type\": \"transaction\",\n" +
                    "        \"algorithm\": \"AEAD_AES_256_GCM\",\n" +
                    "        \"ciphertext\": \"\",\n" +
                    "        \"associated_data\": \"\",\n" +
                    "        \"nonce\": \"\"\n" +
                    "    }\n" +
                    "}")
            @RequestBody String requestBody,
            HttpServletRequest request) throws Exception {
        // 构造 RequestParam
        System.out.println("Wechatpay-Serial:"+request.getHeader("Wechatpay-Serial"));
        System.out.println("Wechatpay-Nonce:"+request.getHeader("Wechatpay-Nonce"));
        System.out.println("Wechatpay-Signature："+request.getHeader("Wechatpay-Signature"));
        System.out.println(""+request.getHeader("Wechatpay-Timestamp"));
        System.out.println("Wechatpay-Signature-Type: "+request.getHeader("Wechatpay-Signature-Type"));
        System.out.println("requestBody: "+requestBody);
        RequestParam requestParam = new RequestParam.Builder()
                .serialNumber(request.getHeader("Wechatpay-Serial"))
                .nonce(request.getHeader("Wechatpay-Nonce"))
                .signature(request.getHeader("Wechatpay-Signature"))
                .timestamp(request.getHeader("Wechatpay-Timestamp"))
                .signType(request.getHeader("Wechatpay-Signature-Type"))
                .body(requestBody)
                .build();

        // 如果已经初始化了 RSAAutoCertificateConfig，可直接使用
        // 没有的话，则构造一个
//        NotificationConfig config = wxPayNotifyImpl_v3.buildConfig();
        NotificationConfig config = (NotificationConfig)SpringTool.getSpringBean(RSAAutoCertificateConfig.class);
        // 初始化 NotificationParser
        NotificationParser parser = new NotificationParser(config);

        try {
            // 以支付通知回调为例，验签、解密并转换成 Transaction
            Transaction transaction = parser.parse(requestParam, Transaction.class);

            if (Objects.equals(transaction.getTradeState(), Transaction.TradeStateEnum.SUCCESS)){
                //处理业务逻辑
                //通知微信支付成功
                System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>");
                System.out.println("transaction: "+transaction.getMchid());
                System.out.println("transaction: "+transaction.getOutTradeNo());
                System.out.println("transaction: "+transaction.getTradeState());
                System.out.println("transaction: "+transaction.getAppid());
                System.out.println("transaction: "+transaction.getTransactionId());
                wxPayServiceImpl_v3.updateResultAfterWxNotify(transaction, requestBody);
                // 处理成功，返回 200 OK 状态码
                return ResponseEntity.status(HttpStatus.OK).build();
            }
        } catch (ValidationException e) {
            // 签名验证失败，返回 401 UNAUTHORIZED 状态码
            LogTool.error(this.getClass(), "sign verification failed", e);
            return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
        }

        // 如果处理失败，应返回 4xx/5xx 的状态码，例如 500 INTERNAL_SERVER_ERROR
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
    }
}
